home *** CD-ROM | disk | FTP | other *** search
/ Compendium Deluxe 1 / LSD Compendium Deluxe 1.iso / a / text / manipulation / cv.lha / cv / cvt / cvt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-31  |  10.1 KB  |  343 lines

  1. /*                                                               -*- C -*-
  2.  *  CVT.C
  3.  *
  4.  *  (c)Copyright 1991-93 by Tobias Ferber, All Rights Reserved.
  5.  */
  6.  
  7. #include <ctype.h>
  8. #include <stdio.h>
  9. #include <stdarg.h>
  10. #include <stdlib.h>
  11.  
  12. static char rcs_id[]= "$VER: $Id: cvt.c 1.6 93/09/11 15:53:29 tf Exp $";
  13.  
  14. #include "cvt.h"
  15.  
  16.  
  17. /*** / CVTOPEN / ***/
  18.  
  19. FILE *cvtopen(char *fname)
  20. /* cvtopen() "offnet ein (level 3) Textfile zum lesen, wobei zun"achst
  21.  * im aktuellen Verzeichnis nach 'fname' und 'fname.cvt' gesucht wird.
  22.  * Wenn da nix ist, werden die durch PSEP getrennten Pfade aus der
  23.  * Environment Variablen ENV_CVSCRIPTS davorgebaut und dort nachgesehen.
  24.  * Der zur"uckgegebene FILE * kann mit fclose() geschlossen werden. */
  25. {
  26.   FILE *fp= NIL(FILE);
  27.   if(fname)
  28.   { char pname[MAXIMUM_PATHNAME_LENGTH];
  29.     strcpy(pname,fname);
  30. #ifdef DEBUG
  31.     if(debuglevel >= 1)
  32.       printf("> cvtopen() trying '%s'\n",pname);
  33. #endif
  34.     if(!(fp=fopen(pname,"r")))
  35.     { strcat(pname,CVT_EXT);
  36. #ifdef DEBUG
  37.       if(debuglevel >= 1)
  38.         printf("                   '%s'\n",pname);
  39. #endif
  40.       if(!(fp=fopen(pname,"r")))
  41.       { char *ep= getenv(ENV_CVSCRIPTS);
  42.         while(!fp && ep && *ep)
  43.         { int i;
  44.           for(i=0; *ep && (pname[i]= *ep++) != PSEP ; i++) ;
  45.           if(i>0)
  46.           { if(pname[i-1]!='\\' && pname[i-1]!=':' && pname[i-1]!='/')
  47.               pname[i++]= PSLASH;
  48.             pname[i]= '\0';
  49.             strcat(pname,fname);
  50. #ifdef DEBUG
  51.             if(debuglevel >= 1)
  52.               printf("                   '%s'\n",pname);
  53. #endif
  54.             if(!(fp=fopen(pname,"r")))
  55.             { strcat(pname,CVT_EXT);
  56. #ifdef DEBUG
  57.               if(debuglevel >= 1)
  58.                 printf("                   '%s'\n",pname);
  59. #endif
  60.               fp= fopen(pname,"r");
  61.             }
  62.           }
  63.         }
  64.       }
  65.     }
  66.   }
  67.   return fp;
  68. }
  69.  
  70.  
  71. /*** / PARSEFILE / ***/
  72.  
  73. int parsefile(FILE *fp)
  74. /* liest ein Scriptfile von 'fp' ein und baut die crules auf */
  75. {
  76.   crule_t *rp;
  77.  
  78. #ifdef DEBUG
  79.   if(debuglevel >= 1)
  80.     printf("Starting parse\n");
  81. #endif
  82.  
  83.   while(!feof(fp) && global_numerrors < global_maxerrors)
  84.   {
  85.     if( rp= readcrule(fp) )
  86.     {
  87.       if( addcrule(rp) )
  88.       { 
  89.         lerror(rp->ln,"lhs is ambiguous!");
  90.  
  91. #ifdef DEBUG
  92.         if(debuglevel >= 2)
  93.           print_crule(rp);
  94. #endif /* DEBUG */
  95.  
  96.       }
  97.     }
  98.   }
  99.  
  100. #ifdef DEBUG
  101.   if(debuglevel >= 1)
  102.     printf("> parsefile()  collected %ld rules,  %ld errors\n"
  103.            "Exiting parse\n", global_numrules, global_numerrors);
  104. #endif
  105.  
  106.   readcrule( NIL(FILE) );
  107.  
  108.   return global_numerrors;
  109. }
  110.  
  111.  
  112. /*** / PUTRHS / ***/
  113.  
  114. void putrhs(crule_t *rp)
  115. /* screibt das Pendant (rhs) zu der lhs von 'rp' nach 'fout' raus */
  116. { if(rp && rp->rhs)
  117.   { int n;
  118.     for(n=0; n<rp->r; n++)
  119.       fputc((rp->rhs)[n],fout);
  120.   }
  121.   /* otherwise substitute lhs to nothing */
  122. }
  123.  
  124.  
  125. /*** / TAKEITEASY / ***/
  126.  
  127. void takeiteasy(void)
  128. /* konvertiert 'fin' nach 'fout', falls global_maxlhs <= 1 ist */
  129. { while(!feof(fin))
  130.   { char c=fgetc(fin);
  131.     if(!feof(fin)) /* do NOT compare c!=EOF ! */
  132.     { int r= (int)(c & 0xFF);
  133.       if(crules[r]) putrhs(crules[r]);
  134.       else fputc(c,fout);
  135.     }
  136.   }
  137. }
  138.  
  139.  
  140. /* convert scanner modes */
  141. typedef enum { outer_mode,   /* reading chars */
  142.                collect_mode, /* collecting chars for a match */
  143.                look_mode,    /* looking for the first rule */
  144.                match_mode,   /* trying to match buffered chars */
  145.                flush_mode    /* flushing collected chars */
  146.              } csmode_t;
  147.  
  148.  
  149. /*** / DOTHEHARDPART / ***/
  150.  
  151. int dothehardpart(void)
  152. {
  153.   if(global_maxlhs<=1) takeiteasy(); /* optimize speed, better performance */
  154.   else
  155.   { char *cbuf, c;
  156.     int l=0;  /* cbuf index */
  157.     crule_t *ccr= NIL(crule_t); /* current crule */
  158.     csmode_t smode= outer_mode;
  159.     cbuf= malloc(global_maxlhs * sizeof(char));
  160.     if(!cbuf)
  161.     { echo("Ran out of memory to allocate %d bytes lhs buffer",
  162.         global_maxlhs);
  163.       return 1;
  164.     }
  165.  
  166.     /* c==EOF is allowed! do NOT use the following shortcut
  167.      * while((c=fgetc(fin))!=EOF &! feof(fin)) */
  168.  
  169.     while(!feof(fin))
  170.     { c= fgetc(fin);
  171.       if(!feof(fin)) do switch(smode)
  172.       {
  173.         case outer_mode:
  174.          /* In diesem scanner mode wird das eingelesene Zeichen
  175.           * + wieder rausgeschrieben, wenn keine Regeln daf"ur existieren.
  176.           *   Der scanner bleibt dann im outer_mode.
  177.           * + in sein Pendant "ubersetzt und dieses rausgeschrieben, wenn
  178.           *   die Regel keinen rechten Kontext f"ur dieses Zeichen vorsieht.
  179.           * + gepuffert und in den collect_mode "ubergegangen, wenn ein rechter
  180.           *   Kontext "uberpr"uft werden mu\3.
  181.           *   Hierbei wird der Kontext der obersten Regel angestrebt.
  182.           */
  183. #ifdef DEBUG
  184.           if(debuglevel >= 4)
  185.             printf("> outer_mode (c=$%x)\n",c&0xFF);
  186. #endif
  187.           { int r= (int)(c & 0xFF);
  188.             if(ccr= crules[r])
  189.             { if(ccr->l > 1) /* look ahead */
  190.               { l=0;
  191.                 cbuf[l++]= c;
  192.                 smode= collect_mode;
  193.               }
  194.               else putrhs(ccr);
  195.             }
  196.             else fputc(c,fout);
  197.           }
  198.           break;
  199.  
  200.         case collect_mode:
  201.          /* In diesem scanner mode wird "uberpr"uft, ob das eingelesene
  202.           * Zeichen in den rechten Kontext der aktuellen Regel 'ccr' pa\3t
  203.           * und in diesem Fall gepuffert.  Wenn damit der gesamte Kontext
  204.           * erf"ullt ist, wird das Pendant rausgeschrieben und in den
  205.           * outer_mode zur"uckgekehrt.
  206.           * Pa\3t dieses Zeichen nicht zum Kontext der aktuellen Regel,
  207.           * so wird in den match_mode "ubergegangen.
  208.           */
  209. #ifdef DEBUG
  210.           if(debuglevel >= 4)
  211.           { printf("> collect_mode (l=%d) for ",l);
  212.             { int i; for(i=0; i<ccr->l; i++) putchar((ccr->lhs)[i]); }
  213.             putchar('\n');
  214.           }
  215. #endif /* DEBUG */
  216.           if((ccr->lhs)[l]==(cbuf[l]=c))
  217.           { if(ccr->l==l+1) /* lhs matched */
  218.             { putrhs(ccr);
  219.               smode= outer_mode;
  220.             }
  221.             else ++l;
  222.           }
  223.           else { ++l; smode= match_mode; }
  224.           break;
  225.  
  226.         case look_mode:
  227.          /* In diesem scanner mode wird geschaut ob die gepufferten
  228.           * Zeichen den rechten Kontext aus der ersten Regel f"ur das
  229.           * oberste Pufferzeichen bilden.  Ist dies der Fall, so
  230.           * werden die zum Kontext geh"orenden Zeichen aus dem Puffer
  231.           * entfernt, deren Pendant ausgegeben und im look_mode
  232.           * verblieben.  Sind noch nicht gen"ugend Zeichen gelesen,
  233.           * so wird in den collect_mode, ansonsten in den match_mode
  234.           * "ubergegangen.
  235.           */
  236. #ifdef DEBUG
  237.           if(debuglevel >= 4)
  238.             printf("> look_mode (l=%d)\n",l);
  239. #endif
  240.           if(l>0)
  241.           { int r= (int)(cbuf[0] & 0xFF);
  242.             if(ccr= crules[r])
  243.             { int n, L; /* L := MIN(l,ccr->l) */
  244.               L= (l <= ccr->l) ? l : ccr->l;
  245.               for(n=0; n<L && (ccr->lhs)[n]==cbuf[n]; n++) ;
  246. #ifdef DEBUG
  247.               if(debuglevel >= 4)
  248.               {
  249.                 printf("  L=%d, l=%d, ccr->l=%d, n=%d trying ",L,l,ccr->l,n);
  250.                 { int i; for(i=0; i<ccr->l; i++) putchar((ccr->lhs)[i]); }
  251.                 putchar('\n');
  252.               }
  253. #endif /* DEBUG */
  254.               if(n == ccr->l) /* lhs matched */
  255.               { putrhs(ccr);
  256.                 l-= ccr->l;
  257.                 if(l>0) /* some chars left */
  258.                 { int i;
  259.                   for(i=0; i<=l; i++) cbuf[i]= cbuf[n+i];
  260.                   smode= look_mode;
  261.                 }
  262.                 else smode= outer_mode; /* no chars left */
  263.               }
  264.               else if(n==l && l<=ccr->l) smode= collect_mode;
  265.               else smode= match_mode;
  266.             }
  267.             else smode= flush_mode;
  268.           }
  269.           else smode= outer_mode;
  270.           break;
  271.  
  272.  
  273.         case match_mode:
  274.          /* In diesem scanner mode wird versucht eine Regel aus der
  275.           * Liste 'ccr' zu finden, die die gepufferten Zeichen abbaut.
  276.           * Dabei wird der head 'ccr' selbst nicht mehr "uberpr"uft.
  277.           * + Wenn es keine passende Regel gibt, so wird in den flush_mode
  278.           *   "ubergegangen.
  279.           * + Bleiben weitere Zeichen im Puffer "ubrig, so wird in
  280.           *   den look_mode "ubergegangen, es sei denn es
  281.           * + fehlen Zeichen zur "Uberpr"ufung eines Kontextes dann
  282.           *   wird in den collect_mode "ubergegangen.
  283.           * + Ist der Puffer leer, so wird in den outer_mode zur"uckgekehrt.
  284.           */
  285. #ifdef DEBUG
  286.           if(debuglevel >= 4)
  287.             printf("> match_mode (l=%d)\n",l);
  288. #endif
  289.           while((smode==match_mode) && (ccr=ccr->next))
  290.           { int n, L;
  291.             L= (l <= ccr->l) ? l : ccr->l;
  292.             for(n=0; n<L && (ccr->lhs)[n]==cbuf[n]; n++) ;
  293. #ifdef DEBUG
  294.             if(debuglevel >= 4)
  295.             {
  296.               printf("  L=%d, l=%d, ccr->l=%d, n=%d trying ",L,l,ccr->l,n);
  297.               { int i; for(i=0; i<ccr->l; i++) putchar((ccr->lhs)[i]); }
  298.               putchar('\n');
  299.             }
  300. #endif /* DEBUG */
  301.             if(n == ccr->l) /* lhs matched */
  302.             { putrhs(ccr);
  303.               l-= ccr->l;
  304.               if(l>0) /* some chars left */
  305.               { int i;
  306.                 for(i=0; i<=l; i++) cbuf[i]= cbuf[n+i];
  307.                 smode= look_mode;
  308.               }
  309.               else smode= outer_mode; /* no chars left */
  310.             }
  311.             else if(n==l && l<=ccr->l) smode= collect_mode;
  312.           }
  313.           if(smode==match_mode)
  314.             smode= flush_mode; /* couln't match this one */
  315.           break;
  316.  
  317.         case flush_mode:
  318.          /* In diesem scanner mode wird das erste Zeichen des Puffers
  319.           * aus diesem entfernt und im Klartext rausgeschrieben.
  320.           * Wenn der Puffer dadurch leer wurde, wird in den outer_mode
  321.           * "ubergegangen, ansonsten in den look_mode.
  322.           */
  323. #ifdef DEBUG
  324.           if(debuglevel >= 4)
  325.             printf("> flush_mode (l=%d)\n",l);
  326. #endif
  327.           fputc(cbuf[0],fout);
  328.           if(--l>=0)
  329.           { int i;
  330.             for(i=0; i<=l; i++)
  331.               cbuf[i]= cbuf[i+1];
  332.             smode= look_mode;
  333.           }
  334.           else smode= outer_mode;
  335.           break;
  336.  
  337.        } while((smode != outer_mode) && (smode != collect_mode));
  338.      }
  339.      /* EOF */
  340.    }
  341.    return 0;
  342. }
  343.